Skip to content

perf(phase 1): low-risk isolated fixes — leaks, bounded cache, main-actor media, micro-opts - #653

Open
mehmetefeaytas wants to merge 6 commits into
Ebullioscopic:devfrom
mehmetefeaytas:feat/perf-phase-1
Open

perf(phase 1): low-risk isolated fixes — leaks, bounded cache, main-actor media, micro-opts#653
mehmetefeaytas wants to merge 6 commits into
Ebullioscopic:devfrom
mehmetefeaytas:feat/perf-phase-1

Conversation

@mehmetefeaytas

@mehmetefeaytas mehmetefeaytas commented Jul 23, 2026

Copy link
Copy Markdown

Phase 1 of a staged performance pass (low-risk, isolated, no behavior change). Each area was implemented and build-verified independently, then merged.

Changes

  • Audio HAL listener leak (SystemMediaControllers.swift): SystemVolumeController added property listeners on every default-device change but never removed the old ones → leaked listeners + duplicate notifications on each headphone swap. Now tracks registrations and removes before re-installing; also memoizes the volume/mute element probes (invalidated on device change).
  • Bounded thumbnail cache (ThumbnailService.swift): unbounded [String: NSImage]NSCache (countLimit 200, totalCostLimit 64 MB, per-image cost). Path-scoped clearing preserved via a tracked key set; drop/dedup logic untouched.
  • Main-actor media publishing (MediaControllers/*): @Published playbackState was written from background stream/websocket/notification contexts ("Publishing changes from background threads"). All state writes moved onto the main actor (state still computed off-main, then a single atomic assignment). Also reuse a static ISO8601DateFormatter instead of allocating per stream line.
  • Stats/battery micro-opts (BatteryActivityManager.swift, StatsManager.swift, utils/CPUSensorCollector.swift): fixed the index-based observer id (shifting ids on removal) → monotonic token dict; periodic ps refresh now respects the 2 s throttle (was bypassed via force: true); collapsed two per-tick getifaddrs walks into one; SMC primary-temperature scan is now early-exit + caches the working key.

Expected gains (estimates — verify with Instruments)

  • Idle CPU −5…10%; long-session RAM growth halted (thumbnail + HAL leak); removes background-publish glitch/crash risk (correctness). No cold-start impact.

Verification

  • xcodebuild … CODE_SIGNING_ALLOWED=NO buildBUILD SUCCEEDED, no new warnings.
  • Suggested on-device: Instruments Allocations (10-min RAM should be flat), Time Profiler (idle CPU), plus behavior check of volume/mute, media playback state, shelf thumbnails, battery HUD.

First of a 4-phase plan; subsequent phases (background-load/energy, main-thread offload, architecture) follow as separate PRs.

Summary by CodeRabbit

  • Bug Fixes

    • Improved reliability and thread-safety of playback state, shuffle, repeat, and position updates across supported music services.
    • Improved volume/mute listener handling when switching devices or routes.
    • Improved battery observer registration/removal behavior.
    • Improved network statistics accuracy during monitoring.
  • Performance Improvements

    • Reduced repeated date formatting and CPU temperature key scanning via reuse/caching.
    • Improved thumbnail caching efficiency and memory management.
    • Reduced unnecessary refresh work and audio listener registration churn.

mehmetefeaytas and others added 5 commits July 23, 2026 23:26
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR moves media playback-state mutations onto the main actor, replaces thumbnail dictionary caching with bounded NSCache, consolidates network interface sampling, manages audio listener lifecycles, tokenizes battery observers, and caches CPU temperature keys.

Changes

Media state coordination

Layer / File(s) Summary
Playback controls and timestamp handling
DynamicIsland/MediaControllers/AmazonMusicController.swift, DynamicIsland/MediaControllers/NowPlayingController.swift
Shared ISO8601 formatters are reused, and shuffle/repeat operations update state on the main actor.
Playback-state publication
DynamicIsland/MediaControllers/{AmazonMusicController,AppleMusicController,NowPlayingController,SpotifyController}.swift
Resolved playback states and Amazon idle transitions are committed through MainActor.run with weak captures.
YouTube Music state transitions
DynamicIsland/MediaControllers/YouTube Music Controller/YouTubeMusicController.swift
Inactive, termination, WebSocket, command, and reconciliation paths now update playback state on the main actor.

Thumbnail cache management

Layer / File(s) Summary
Bounded thumbnail storage and invalidation
DynamicIsland/components/Shelf/Services/ThumbnailService.swift
Thumbnail storage uses cost-limited NSCache with tracked keys for full and path-scoped invalidation while retaining pending-request deduplication.

System monitoring and audio resources

Layer / File(s) Summary
Snapshot-based network metrics
DynamicIsland/managers/StatsManager.swift
Network totals and per-interface metrics derive from a shared interface snapshot, and process refresh uses normal interval gating.
Volume listener lifecycle and element access
DynamicIsland/managers/SystemMediaControllers.swift
Volume listeners are tracked and removed before reinstallation; volume and mute elements are recomputed on access.
CPU temperature key reuse
DynamicIsland/utils/CPUSensorCollector.swift
The last successful primary temperature key is tried first and updated when another candidate succeeds.

Battery observer registration

Layer / File(s) Summary
Token-based observer storage
DynamicIsland/managers/BatteryActivityManager.swift
Observers are stored by generated token, removed by token lookup, and enumerated from dictionary values during notification.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested labels: in progress

Suggested reviewers: ebullioscopic

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main themes of the changes: leak cleanup, bounded caching, main-actor media updates, and small optimizations.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added the in progress This PR/issue is in progress label Jul 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
DynamicIsland/components/Shelf/Services/ThumbnailService.swift (1)

83-86: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Base cache cost on backing pixels if 64 MB is a real memory target.

NSImage.size is not necessarily the underlying pixel size; representation points can differ from pixelsWide/pixelsHigh. Retina or multi-representation thumbnails can therefore be undercounted, allowing substantially more actual image memory than the configured cost limit. (developer.apple.com)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DynamicIsland/components/Shelf/Services/ThumbnailService.swift` around lines
83 - 86, Update estimatedCost(of:) to calculate cache cost from the image
representation’s backing pixel dimensions (pixelsWide and pixelsHigh) rather
than NSImage.size, using the applicable representation for the thumbnail and
preserving the 4-bytes-per-pixel estimate and minimum cost of 1.

Source: MCP tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@DynamicIsland/components/Shelf/Services/ThumbnailService.swift`:
- Line 46: Update the cache-key matching in ThumbnailService’s scoped
invalidation logic to enforce a path boundary: match the exact-file prefix
"\(url.path)_" for file invalidation, or apply a directory-component boundary
predicate if callers require directory-wide invalidation. Preserve invalidation
of intended entries while excluding similarly prefixed unrelated paths.
- Around line 37-39: Update ThumbnailService’s cache bookkeeping so cacheKeys is
removed or kept synchronized with NSCache eviction; store each thumbnail’s path
on its cached wrapper object and use NSCacheDelegate.willEvictObject(_:) to
remove evicted paths, while preserving clearCache(for:) path-based invalidation.

In `@DynamicIsland/managers/BatteryActivityManager.swift`:
- Around line 322-325: Update notifyObservers(event:) to snapshot the current
observer values before entering the callback loop, then iterate over that
snapshot instead of self.observers.values. Preserve the existing main-thread
dispatch and weak-self handling while allowing callbacks to mutate observers
safely.
- Around line 40-41: Make the public observer APIs, including addObserver and
removeObserver, `@MainActor-isolated` so all accesses to observers and
nextObserverToken occur on the main actor, including the event delivery path.
Ensure callers and callback registration/removal preserve this isolation without
introducing unsynchronized registry access.

In `@DynamicIsland/managers/StatsManager.swift`:
- Around line 1078-1099: Update aggregateNetworkStats to return an optional
tuple, preserving nil when snapshots is nil instead of converting failure to
zero. In updateSystemStats, only replace previousNetworkStats when aggregation
succeeds; otherwise retain the existing cached baseline. Keep the explicit zero
fallback for the initial-baseline call sites where no prior state exists.

In `@DynamicIsland/MediaControllers/AmazonMusicController.swift`:
- Around line 302-304: Construct and publish each media state snapshot
atomically on the main actor by reading the current playback state and merging
the incoming payload inside the same update transaction. Apply this to
AmazonMusicController.swift (302-304), NowPlayingController.swift (270-272),
AppleMusicController.swift (165-168), SpotifyController.swift (199-202), and
YouTubeMusicController.swift (448-451); preserve incremental updates while
preventing stale full responses from overwriting newer fields.

---

Nitpick comments:
In `@DynamicIsland/components/Shelf/Services/ThumbnailService.swift`:
- Around line 83-86: Update estimatedCost(of:) to calculate cache cost from the
image representation’s backing pixel dimensions (pixelsWide and pixelsHigh)
rather than NSImage.size, using the applicable representation for the thumbnail
and preserving the 4-bytes-per-pixel estimate and minimum cost of 1.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 03066bbe-58a4-441b-814f-a62eafc3225c

📥 Commits

Reviewing files that changed from the base of the PR and between 503606c and 16c8620.

📒 Files selected for processing (10)
  • DynamicIsland/MediaControllers/AmazonMusicController.swift
  • DynamicIsland/MediaControllers/AppleMusicController.swift
  • DynamicIsland/MediaControllers/NowPlayingController.swift
  • DynamicIsland/MediaControllers/SpotifyController.swift
  • DynamicIsland/MediaControllers/YouTube Music Controller/YouTubeMusicController.swift
  • DynamicIsland/components/Shelf/Services/ThumbnailService.swift
  • DynamicIsland/managers/BatteryActivityManager.swift
  • DynamicIsland/managers/StatsManager.swift
  • DynamicIsland/managers/SystemMediaControllers.swift
  • DynamicIsland/utils/CPUSensorCollector.swift

Comment thread DynamicIsland/components/Shelf/Services/ThumbnailService.swift
Comment thread DynamicIsland/components/Shelf/Services/ThumbnailService.swift
Comment on lines +40 to +41
private var observers: [Int: (BatteryEvent) -> Void] = [:]
private var nextObserverToken: Int = 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

rg -n 'addObserver\(|removeObserver\(byId:' --glob '*.swift'

Repository: Ebullioscopic/Atoll

Length of output: 2580


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "repo status:"
git status --short --untracked-files=no || true
echo
echo "top-level files:"
git ls-files | sed -n '1,80p'
echo
echo "tracetrace files named manager swift:"
git ls-files | rg 'BatteryActivityManager\.swift$|BatteryActivityManager' || true
echo
echo "try reading target Swift file:"
file="$(git ls-files | rg '((^|/)BatteryActivityManager\.swift$)' | head -n1)"
if [ -n "$file" ]; then
  echo "FILE=$file"
  wc -l "$file"
  sed -n '1,140p' "$file"
  echo "----- bottom relevant if any -----"
  sed -n '280,335p' "$file"
fi
echo
echo "tracked Swift occurrences by caller/grep:"
rg -n 'addObserver\(|removeObserver\(byId:' --glob '*.swift' . || true

echo
echo "all swift occurrences in non-lfs files if available:"
rg -n 'addObserver\(|removeObserver\(byId:' . --glob '*.swift' || true

Repository: Ebullioscopic/Atoll

Length of output: 2552


Force main-thread safety for the observer registry.

addObserver and removeObserver share mutable registry state with the delivery path. If either is called from a background thread, it can race with main-thread dictionary reads/writes and token allocation, causing duplicate callbacks, dictionary corruption, or a crash. Make the public observer API @MainActor or protect all registry access with one serial synchronization primitive.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DynamicIsland/managers/BatteryActivityManager.swift` around lines 40 - 41,
Make the public observer APIs, including addObserver and removeObserver,
`@MainActor-isolated` so all accesses to observers and nextObserverToken occur on
the main actor, including the event delivery path. Ensure callers and callback
registration/removal preserve this isolation without introducing unsynchronized
registry access.

Comment thread DynamicIsland/managers/BatteryActivityManager.swift Outdated
Comment thread DynamicIsland/managers/StatsManager.swift
Comment on lines +302 to +304
await MainActor.run { [weak self] in
self?.playbackState = newPlaybackState
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Construct and publish each state snapshot in the same main-actor transaction.

These closures only publish a snapshot; its baseline was read and merged beforehand off-actor. A command/WebSocket/artwork update may modify one field on the main actor before an older full snapshot arrives and overwrites it. Build the next state from self.playbackState inside the same MainActor.run block, or main-actor-isolate the update method.

  • DynamicIsland/MediaControllers/AmazonMusicController.swift#L302-L304: merge the adapter payload from an actor-isolated baseline.
  • DynamicIsland/MediaControllers/NowPlayingController.swift#L270-L272: merge the stream payload from an actor-isolated baseline.
  • DynamicIsland/MediaControllers/AppleMusicController.swift#L165-L168: derive updatedState from an actor-isolated baseline.
  • DynamicIsland/MediaControllers/SpotifyController.swift#L199-L202: derive and publish resolvedState atomically with respect to other state updates.
  • DynamicIsland/MediaControllers/YouTube Music Controller/YouTubeMusicController.swift#L448-L451: prevent full polling/WebSocket responses from reverting incremental updates.
📍 Affects 5 files
  • DynamicIsland/MediaControllers/AmazonMusicController.swift#L302-L304 (this comment)
  • DynamicIsland/MediaControllers/NowPlayingController.swift#L270-L272
  • DynamicIsland/MediaControllers/AppleMusicController.swift#L165-L168
  • DynamicIsland/MediaControllers/SpotifyController.swift#L199-L202
  • DynamicIsland/MediaControllers/YouTube Music Controller/YouTubeMusicController.swift#L448-L451
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DynamicIsland/MediaControllers/AmazonMusicController.swift` around lines 302
- 304, Construct and publish each media state snapshot atomically on the main
actor by reading the current playback state and merging the incoming payload
inside the same update transaction. Apply this to AmazonMusicController.swift
(302-304), NowPlayingController.swift (270-272), AppleMusicController.swift
(165-168), SpotifyController.swift (199-202), and YouTubeMusicController.swift
(448-451); preserve incremental updates while preventing stale full responses
from overwriting newer fields.

- ThumbnailService: reconcile `cacheKeys` against the NSCache once it exceeds the
  count limit so the tracking set stays bounded; match the "<path>_" boundary in
  clearCache(for:) so invalidating /tmp/a no longer evicts /tmp/ab's thumbnails.
- BatteryActivityManager: snapshot observers (Array(values)) before invoking, so a
  callback that adds/removes observers can't trigger a mutation-during-iteration trap.
- StatsManager: preserve the network baseline when getifaddrs fails (nil snapshot)
  instead of collapsing to (0,0), which faked a speed dip and wiped previousNetworkStats.
- SystemMediaControllers: drop the volume/mute element caches — they were read/populated
  from the public API on arbitrary threads while refreshPropertyElements() cleared them on
  callbackQueue (data race). Recompute on access (cheap probe). HAL listener-leak fix retained.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mehmetefeaytas

Copy link
Copy Markdown
Author

Thanks @coderabbitai — addressed in 3193e1d.

✅ Applied

  • ThumbnailService — unbounded cacheKeys: once the tracking set exceeds the NSCache count limit it's reconciled against the cache (filter { cache.object(forKey:) != nil }), so evicted keys don't linger.
  • ThumbnailService — scoped invalidation boundary: clearCache(for:) now matches the "<path>_" prefix (keys are <path>_<w>x<h>), so invalidating /tmp/a no longer evicts /tmp/ab.
  • BatteryActivityManager — mutation during iteration: iterate Array(observers.values) (a snapshot) so a callback adding/removing observers can't trap.
  • StatsManager — network baseline on getifaddrs failure: a nil snapshot now preserves previousNetworkStats (currentNetworkStats = snapshot != nil ? aggregate(...) : previous) instead of collapsing to (0,0) — no fake speed dip, no baseline wipe.
  • SystemMediaControllers — unsynchronized element caches: reverted the cachedVolumeElements/cachedMuteElements micro-optimization (it raced between the public API's arbitrary thread and refreshPropertyElements() on callbackQueue). Elements are recomputed per access (cheap probe). The HAL property-listener leak fix — the point of this change — is retained.

↩️ Deferred (with rationale)

  • AmazonMusicController / NowPlayingController — build+publish in one main-actor transaction (Heavy lift): Phase 1 already moved the @Published writes onto the main actor; the residual is that the baseline is read/merged off-actor, so a concurrent main-actor field update could be clobbered by a slightly older snapshot. A correct fix means main-actor-isolating the whole merge (or the controllers), which is a larger concurrency restructure I don't want to land unverified in this low-risk phase. Tracking it as a follow-up.

Tests: added standalone logic tests for the path-boundary match, observer-token add/remove (no id shift + snapshot-during-mutation), and network-baseline-on-failure — all pass. App builds clean (BUILD SUCCEEDED).

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@mehmetefeaytas Thanks for the thorough follow-up. The fixes and focused tests cover the reported issues well—especially preserving the network baseline on getifaddrs failure and reverting the unsynchronized HAL element caches while retaining listener cleanup.

The main-actor merge/publication race is reasonably deferred from this low-risk phase. Would you like me to open a GitHub follow-up issue for it?

🐇 ✅


✏️ Learnings added
Learnt from: mehmetefeaytas
URL: https://github.com/Ebullioscopic/Atoll/pull/653

Timestamp: 2026-07-23T21:44:59.556Z
Learning: In `DynamicIsland/managers/SystemMediaControllers.swift`, volume and mute HAL property-element caching must not be accessed unsafely across the public API's arbitrary calling threads and `callbackQueue`; recomputing the inexpensive probes per access is preferred unless synchronization or actor isolation is introduced. The HAL property-listener cleanup remains required.

Learnt from: mehmetefeaytas
URL: https://github.com/Ebullioscopic/Atoll/pull/653

Timestamp: 2026-07-23T21:44:59.556Z
Learning: In `DynamicIsland/MediaControllers/AmazonMusicController.swift` and `DynamicIsland/MediaControllers/NowPlayingController.swift`, publishing `playbackState` on the main actor does not by itself make off-actor state reads and merges atomic. A full correctness fix requires main-actor-isolating the complete merge/publish transaction (or the controllers) to prevent an older snapshot from overwriting concurrent main-actor updates.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
DynamicIsland/managers/SystemMediaControllers.swift (2)

223-231: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Do not discard the active listeners before the replacement device is validated.

If resolveDefaultDevice() transiently fails and returns 0, or the new device cannot be probed, this removes the working listeners and installs none. Preserve the existing registration until the new device/listener set is successfully resolved, or retain the previous device on resolution failure.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DynamicIsland/managers/SystemMediaControllers.swift` around lines 223 - 231,
Update installVolumeListeners(for:) to validate resolveElement and the complete
replacement listener setup before calling removeVolumeListeners(). If the new
device resolves to 0 or cannot be probed, preserve the existing volumeElement
and listeners; only replace the current registration after the new
device/listener set is successfully resolved.

253-265: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Retain registrations when listener removal fails.

After a non-noErr removal, the HAL listener may still be active, but removeAll() drops the device/address/block needed to retry removal. Repeated route changes can therefore leak listeners and produce duplicate callbacks. Keep failed registrations for retry, or abort the listener-set swap until cleanup succeeds.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DynamicIsland/managers/SystemMediaControllers.swift` around lines 253 - 265,
The removeVolumeListeners method currently discards all registrations even when
AudioObjectRemovePropertyListenerBlock fails. Preserve registrations whose
removal returns a non-noErr status so they can be retried, while removing
successfully deregistered entries; ensure volumeListenerRegistrations is only
updated with the failed registrations rather than cleared unconditionally.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@DynamicIsland/managers/SystemMediaControllers.swift`:
- Around line 223-231: Update installVolumeListeners(for:) to validate
resolveElement and the complete replacement listener setup before calling
removeVolumeListeners(). If the new device resolves to 0 or cannot be probed,
preserve the existing volumeElement and listeners; only replace the current
registration after the new device/listener set is successfully resolved.
- Around line 253-265: The removeVolumeListeners method currently discards all
registrations even when AudioObjectRemovePropertyListenerBlock fails. Preserve
registrations whose removal returns a non-noErr status so they can be retried,
while removing successfully deregistered entries; ensure
volumeListenerRegistrations is only updated with the failed registrations rather
than cleared unconditionally.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 03f25ccf-1fb5-415d-bcfe-6c5a604d6ab4

📥 Commits

Reviewing files that changed from the base of the PR and between 16c8620 and 3193e1d.

📒 Files selected for processing (4)
  • DynamicIsland/components/Shelf/Services/ThumbnailService.swift
  • DynamicIsland/managers/BatteryActivityManager.swift
  • DynamicIsland/managers/StatsManager.swift
  • DynamicIsland/managers/SystemMediaControllers.swift
🚧 Files skipped from review as they are similar to previous changes (3)
  • DynamicIsland/managers/BatteryActivityManager.swift
  • DynamicIsland/components/Shelf/Services/ThumbnailService.swift
  • DynamicIsland/managers/StatsManager.swift

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

in progress This PR/issue is in progress

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant